﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace MabiCommerce
{
    public partial class Form1 : Form
    {
        List<CommerceRun> runs;
        Action<Dictionary<string, Dictionary<string, int>>, string, string> uploader;
        
        public Form1()
        {
            InitializeComponent();
            uploader = new Action<Dictionary<string, Dictionary<string, int>>, string, string>(uploadToServer);
        }
        protected override void OnLoad(EventArgs e)
        {
            Erinn.Initialize();
            foreach (Town t in Erinn.Towns)
            {
                townList.Items.Add(t.Name);
            }
            foreach (Transport t in Erinn.AllTransports)
            {
                transportImages.Images.Add(t.Name, Image.FromFile(@"data\icons\transports\" + t.Name + ".png"));

                if (t.Required)
                    Erinn.AvailableTransports.Add(t);

                CheckBox c = new CheckBox();
                c.Size = new System.Drawing.Size(90, 15);
                c.BackColor = Color.Transparent;
                c.ForeColor = Color.White;
                c.Checked = t.Required;
                c.Name = t.Name;
                c.Text = t.Name;
                c.CheckedChanged += new EventHandler(c_CheckedChanged);

                iHavePanel.Controls.Add(c);
            }
            updateAvailableTransportList();
            transportDropDown.SelectedIndex = 0;
            serverName.SelectedIndex = 0;
            townList.SelectedIndex = 0;

            base.OnLoad(e);
        }

        private const int WM_NCHITTEST = 0x84;
        private const int HTCLIENT = 0x1;
        private const int HTCAPTION = 0x2;
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (m.Msg == WM_NCHITTEST && (int)m.Result == HTCLIENT)
            {
                int x = (short)(m.LParam.ToInt32() & 0x0000FFFF);
                int y = (short)((m.LParam.ToInt32() & 0xFFFF0000) >> 16);
                Point mousePos = PointToClient(new Point(x, y));

                if (13 <= mousePos.X && mousePos.X <= 800 && 70 <= mousePos.Y && mousePos.Y <= 91)
                    m.Result = (IntPtr)HTCAPTION;
                else if (mousePos.Y < 70) //If the mouse is above the titlebar (by the emblem)
                    m.Result = (IntPtr)(0); //Return "Nowhere" 
            }
        }

        void c_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox c = (CheckBox)sender;
            Transport myTransport = Erinn.AllTransports.Find(new Predicate<Transport>((t) => { return t.Name.Equals(c.Name); }));
            if (myTransport.Required && !c.Checked)
                c.Checked = true;
            if (c.Checked)
            {
                Erinn.AvailableTransports.Add(myTransport);
            }
            else
                Erinn.AvailableTransports.Remove(myTransport);

            updateAvailableTransportList();
            transportDropDown.SelectedIndex = 0;
        }

        private void updateAvailableTransportList()
        {
            transportDropDown.Items.Clear();
            foreach (Transport t in Erinn.AllTransports)
            {
                ComboBoxExItem c = new ComboBoxExItem();
                c.ImageIndex = transportImages.Images.IndexOfKey(t.Name);
                c.Text = t.Name;
                c.Background = (Erinn.AvailableTransports.Contains(t)) ? Color.FromArgb(157, 142, 104) : Color.DarkGray;
                transportDropDown.Items.Add(c);
            }
        }

        private void townList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (townList.SelectedItem == null)
                return;
            runView.Items.Clear();
            townIcon.Load(@"data\icons\towns\" + townList.SelectedItem + ".png");
            Town theTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); }));
            updateItemDisplay(theTown);

            Dictionary<string, Dictionary<string, int>> serverProfits;

            if (((string)serverName.SelectedItem).Equals("Auto"))
            {
                serverProfits = Web.GetFromIP(townList.SelectedItem.ToString());
            }
            else
            {
                serverProfits = Web.GetFromServer(serverName.SelectedItem.ToString(), townList.SelectedItem.ToString());
            }
            if (serverProfits == null)
                return;

            foreach (KeyValuePair<string, Dictionary<string, int>> itemEntry in serverProfits)
            {
                try
                {
                    Item theItem = theTown.Items.Find(new Predicate<Item>((i) => { return i.Name.Equals(itemEntry.Key); }));
                    foreach (KeyValuePair<string, int> townProfit in itemEntry.Value)
                    {
                        try
                        {
                            Town theDestTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townProfit.Key); }));
                            theItem.Profits[theDestTown] = townProfit.Value;
                        }
                        catch
                        {
                            continue;
                        }
                    }
                }
                catch
                {
                    continue;
                }

            }
            updateItemDisplay(theTown); //Catch any updated profits
       }

        private void updateItemDisplay(Town theTown)
        {
            itemBox.BeginUpdate();
            itemBox.Items.Clear();
            itemImages.Images.Clear();
            foreach (Item i in theTown.Items)
            {
                itemImages.Images.Add(i.Name, Image.FromFile(@"data\icons\items\" + i.Name + ".png"));
                ListViewItem newLVI = new ListViewItem();
                newLVI.ImageKey = newLVI.Name = i.Name;
                newLVI.SubItems.Add(i.Name);
                if (merchRatingUD.Value < i.MerchantRating)
                {
                    newLVI.BackColor = Color.Silver;
                    newLVI.SubItems.Add("Merchant rating needed: " + i.MerchantRating);
                }
                else
                {
                    newLVI.BackColor = itemBox.BackColor;
                    newLVI.SubItems.Add("Weight: " + i.Weight);
                }
                itemBox.Items.Add(newLVI);
            }
            itemBox.EndUpdate();
            itemBox.Items[0].Selected = true;
        }

        private void merchRatingUD_ValueChanged(object sender, EventArgs e)
        {
            Town theTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); }));
            foreach (Item i in theTown.Items)
            {
                ListViewItem lvi = itemBox.Items.Find(i.Name, false)[0];
                if (i.MerchantRating > merchRatingUD.Value)
                {
                    lvi.BackColor = Color.Silver;
                    lvi.SubItems[2].Text = "Merchant rating needed: " + i.MerchantRating;
                }
                else
                {
                    lvi.BackColor = itemBox.BackColor;
                    lvi.SubItems[2].Text = "Weight: " + i.Weight;
                }
            }
        }

        private void minimizeBtn_Click(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
        }

        private void closeBtn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        volatile bool profitPanelUpdating = false;

        private void itemBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (itemBox.SelectedIndices.Count == 0)
                return;
            profitPanelUpdating = true;
            Town theTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); }));
            Item theItem = theTown.Items.Find(new Predicate<Item>((i) => {return i.Name.Equals(itemBox.SelectedItems[0].SubItems[1].Text);}));
            itemName.Text = theItem.Name;
            weightLabel.Text = "Weight: " + theItem.Weight;
            inventoryLabel.Text = "Inventory: " + theItem.NumberAvailable; //TODO: Allow Editing

            foreach (Control c in profitPanel.Controls)
            {
                profitPanel.Controls.Remove(c);
                c.Dispose();
            }

            profitPanel.Controls.Clear();

            int y = 4;
            foreach (KeyValuePair<Town, int> kvp in theItem.Profits)
            {
                Label l = new Label();
                l.AutoSize = true;
                l.ForeColor = Color.FromArgb(78,53,10);
                l.Text = kvp.Key.Name;
                l.Location = new Point(4, y);

                NumericUpDown nud = new NumericUpDown();
                //nud.AutoSize = true;
                nud.Size =new Size(50, 10);
                nud.Minimum = Int32.MinValue;
                nud.Maximum = Int32.MaxValue;
                nud.Location = new Point(120, y);
                nud.Name = kvp.Key.Name + "|" + theItem.Name;

                profitPanel.Controls.Add(l);
                profitPanel.Controls.Add(nud);
                y += nud.Size.Height;

                nud.Enter += new EventHandler(nud_GotFocus);

                nud.ValueChanged += new EventHandler(nud_ValueChanged);
                nud.Value = kvp.Value;
            }
            profitPanelUpdating = false;
        }

        void nud_GotFocus(object sender, EventArgs e)
        {
            NumericUpDown nud = (NumericUpDown)sender;
            nud.Select(0, nud.Text.Length);
        }

        void nud_ValueChanged(object sender, EventArgs e)
        {
            NumericUpDown nud = (NumericUpDown)sender;
            if (nud.Value == 0)
                nud.ForeColor = Color.Black;
            else if (nud.Value > 0)
                nud.ForeColor = Color.Red;
            else
                nud.ForeColor = Color.Blue;

            if (profitPanelUpdating)
                return;

            string[] parts = nud.Name.Split('|');

            Town currentTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); }));
            Item theItem = currentTown.Items.Find(new Predicate<Item>((i) => { return i.Name.Equals(parts[1]); }));
            Town theTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(parts[0]); }));

            theItem.Profits[theTown] = (int)nud.Value;
            if (!theItem.Touched.Contains(theTown))
                theItem.Touched.Add(theTown);

        }

        private void comboBoxEx1_SelectedIndexChanged(object sender, EventArgs e)
        {
            Transport t = Erinn.AllTransports.Find(new Predicate<Transport>((tport) => { return tport.Name.Equals(((ComboBoxExItem)transportDropDown.SelectedItem).Text); }));
            currentWeightBar.Maximum = t.MaxWeight;
            currentWeightLabel.Text = "0/" + t.MaxWeight;
        }

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine(e.Location); //For easily finding the custom titlebar region
        }

        private void calculateCommerceRuns()
        {
            runs = new List<CommerceRun>();

            Town currentTown = Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); }));
            foreach (Item i in currentTown.Items)
            {
                if (i.MerchantRating > merchRatingUD.Value)
                    continue;
                foreach (Town t in Erinn.Towns)
                {
                    if (t == currentTown)
                        continue; //We can't sell to the town we're currently at >_>
                    Route r = Erinn.Routes.Find(new Predicate<Route>((rt) => { return rt.EndTowns.Contains(currentTown) && rt.EndTowns.Contains(t); } ));
                    foreach (Transport trans in Erinn.AvailableTransports)
                    {
                        runs.Add(new CommerceRun(r, trans, i));
                    }
                }
            }

            runs.Sort(); //Sorts into smallest profit first. Oops!
            runs.Reverse(); //Clearer than modifying ICompareable on routes

            updateRunDisplay();
        }

        private void updateRunDisplay()
        {
            runView.BeginUpdate();
            runView.Items.Clear();
            foreach (CommerceRun r in runs)
            {
                ListViewItem lvi = new ListViewItem(r.destTown.Name);
                lvi.SubItems.Add(r.ProfitPerSecond.ToString());
                lvi.SubItems.Add(r.TheItem.Name);
                lvi.SubItems.Add(r.NumberOfItems.ToString());
                lvi.SubItems.Add(r.TransportMode.Name);
                lvi.SubItems.Add(r.Profit.ToString("n"));
                lvi.SubItems.Add(r.TotalTime.ToString());
                runView.Items.Add(lvi);
            }
            runView.EndUpdate();
            runView.Items[0].Selected = true;
        }

        private void calculateBtn_Click(object sender, EventArgs e)
        {
            Dictionary<string, Dictionary<string, int>> profits = getTouchedPrices();
            uploader.BeginInvoke(profits,(string)serverName.SelectedItem, townList.SelectedItem.ToString(), null, null);
            calculateCommerceRuns();
        }

        private void uploadToServer(Dictionary<string, Dictionary<string, int>> profits, string server, string town)
        {
            CheckForIllegalCrossThreadCalls = false;
            if (server.Equals("Auto"))
            {
                Web.PostToIP(town, profits);
            }
            else
            {
                Web.PostToServer(server, town, profits);
            }
        }

        private Dictionary<string, Dictionary<string, int>> getTouchedPrices()
        {
            Dictionary<string, Dictionary<string, int>> ret = new Dictionary<string, Dictionary<string, int>>();
            foreach (Town t in Erinn.Towns)
            {
                foreach (Item i in t.Items)
                {
                    if (i.Touched.Count == 0)
                        continue;
                    Dictionary<string, int> touchedProfits = new Dictionary<string, int>();
                    foreach (Town touched in i.Touched)
                    {
                        touchedProfits.Add(touched.Name, i.Profits[touched]);
                    }
                    i.Touched.Clear();
                    ret.Add(i.Name, touchedProfits);
                }
            }
            return ret;
        }

        private void runView_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (runView.SelectedIndices.Count == 0)
                return;
            CommerceRun r = runs[runView.SelectedIndices[0]];
            transportDropDown.SelectedIndex = Erinn.AllTransports.IndexOf(r.TransportMode);
            currentWeightLabel.Text = r.TheItem.Weight * r.NumberOfItems + "/" + r.TransportMode.MaxWeight;
            currentWeightBar.Value = r.TheItem.Weight * r.NumberOfItems;
        }

        private void mapitBtn_Click(object sender, EventArgs e)
        {
            if (runView.SelectedIndices.Count == 0)
            {
                MessageBox.Show("You need to select a route before you can map it!", "Please select a route", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            Map m = new Map(runs[runView.SelectedIndices[0]], Erinn.Towns.Find(new Predicate<Town>((t) => { return t.Name.Equals(townList.SelectedItem); })));
            m.Location = this.Location;
            m.Show();
        }

        private void serverName_SelectedIndexChanged(object sender, EventArgs e)
        {
            townList_SelectedIndexChanged(null, null);
        }
    }
    public class TransparentListView : ListView
    {

    }
}
